package com.shelpe.services.sinbad.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Controller;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.async.DeferredResult;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Shape;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonInclude.Include;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.shelpe.services.sinbad.controller.LogDto.LogNoteable;
import com.shelpe.services.sinbad.dao.RptCustomerMapper;
import com.shelpe.services.sinbad.dto.UserViewDto;
import com.shelpe.services.sinbad.entity.jpa.Message;
import com.shelpe.services.sinbad.entity.jpa.MessageTopics;
import com.shelpe.services.sinbad.entity.jpa.MessageTopics.DialogStatus;
import com.shelpe.services.sinbad.entity.jpa.MessageTopics.FlagForm;
import com.shelpe.services.sinbad.entity.jpa.User;
import com.shelpe.services.sinbad.entity.jpa.UserLevelReport;
import com.shelpe.services.sinbad.entity.mongo.AccountBalance;
import com.shelpe.services.sinbad.entity.mongo.BalanceAndRealtimeCostErrorLog;
import com.shelpe.services.sinbad.model.RptCustomer;
import com.shelpe.services.sinbad.model.RptCustomerParam;
import com.shelpe.services.sinbad.model.RptKeyword;
import com.shelpe.services.sinbad.model.RptKeywordParam;
import com.shelpe.services.sinbad.readdao.ReadRptKeywordMapper;
import com.shelpe.services.sinbad.repository.jpa.MessageRepository;
import com.shelpe.services.sinbad.repository.jpa.MessageTopicsRepository;
import com.shelpe.services.sinbad.repository.jpa.UserLevelReportRepository;
import com.shelpe.services.sinbad.repository.jpa.UserRepository;
import com.shelpe.services.sinbad.repository.mongo.AccountBalanceRepository;
import com.shelpe.services.sinbad.repository.mongo.BalanceAndRealtimeCostErrorLogRepository;
import com.shelpe.services.sinbad.service.CreativeService;
import com.shelpe.services.sinbad.service.ProductService;
import com.shelpe.services.sinbad.service.RptCustomerService;
import com.shelpe.services.sinbad.service.RptKeywordService;
import com.shelpe.services.sinbad.service.simbaproxy.SimbaProxyBaseDto;
import com.shelpe.services.sinbad.service.simbaproxy.UserClient;
import com.shelpe.services.sinbad.service.simbaproxy.UserClient.AuthsignResponse;
import com.shelpe.services.sinbad.service.simbaproxy.UserClient.GetBalanceResponse;
import com.shelpe.services.sinbad.service.simbaproxy.UserClient.GetRtrCustDto;
import com.shelpe.services.sinbad.service.simbaproxy.UserClient.GetRtrCustResponse;
import com.shelpe.services.sinbad.utils.DateUtil;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

@Controller
@RequestMapping("/sinbadservice")
@Slf4j
@Api(value = "用户相关的API", consumes = "application/json")
public class UserController {
	public final static String FORMAT_DAY = "yyyy-MM-dd";

	@Autowired
	ProductService productService;
	@Autowired
	CreativeService creativeService;
	@Autowired
	RptCustomerService rptCustomerService;
	@Autowired
	RptKeywordService rptKeywordService;
	@Autowired
	private MessageRepository messageRepository;
	@Autowired
	private UserRepository userRepository;
	@Autowired
	private UserClient userClient;
	@Autowired
	private UserLevelReportRepository userLevelReportRepository;
	@Autowired
	private MessageTopicsRepository messageTopicsRepository;
	@Autowired
	private BalanceAndRealtimeCostErrorLogRepository balanceAndRealtimeCostErrorLogRepository;
	@Autowired
	private ObjectMapper objectMapper;
	@Autowired
	private ReadRptKeywordMapper readRptKeywordMapper;
	@Autowired
	private AccountBalanceRepository accountBalanceRepository;
	@Autowired
	private RptCustomerMapper rptCustomerMapper;

	@ApiOperation(value = "获取用户登陆权限签名")
	@RequestMapping(path = "/users/{user_id}", method = RequestMethod.GET)
	@ResponseBody
	public AuthsignResponse findAuthSign(@PathVariable("user_id") long userID) {
		User user = this.userRepository.findOne(userID);
		Assert.notNull(user, "user_not_exist");
		AuthsignResponse res = this.userClient.findAuthsign(user.getNick());

		return res;
	}

	@ApiOperation(value = "查询批量用户")
	@RequestMapping(path = "/users", method = RequestMethod.GET)
	@ResponseBody
	public List<UserViewDto> query(@RequestParam(name = "user_id", required = false) final Long userID,
			@RequestParam(name = "time", required = false) final String time,
			@RequestParam(name = "operation", required = false, defaultValue = "equal") @ApiParam(allowableValues = "equal, lt,gt") final String operation) {
		List<User> pos = this.userRepository.findAll(new Specification<User>() {
			@Override
			public Predicate toPredicate(Root<User> root, CriteriaQuery<?> query, CriteriaBuilder cb) {
				Predicate p = cb.equal(root.get("userType"), 1);
				if (userID != null) {
					p = cb.equal(root.get("userID"), userID);
				}
				if (StringUtils.isNotBlank(time)) {
					if ("lt".equals(operation)) {
						p = cb.and(p, cb.lessThan(root.get("createdTime"), DateUtil.parseDate(time)));
					} else if ("gt".equals(operation)) {
						p = cb.and(p, cb.greaterThan(root.get("createdTime"), DateUtil.parseDate(time)));
					} else {
						p = cb.and(p, cb.equal(root.get("createdTime"), DateUtil.parseDate(time)));
					}
				}

				return p;
			}
		});

		List<UserViewDto> dtos = new ArrayList<UserViewDto>();
		if (pos != null && pos.size() > 0) {
			for (User po : pos) {
				UserViewDto dto = new UserViewDto();
				dto.from(po);
				dtos.add(dto);
			}
		}

		return dtos;
	}

	/**
	 * 创建不基于用户消息
	 * 
	 * @return
	 */
	@ApiOperation(value = "创建不基于用户消息并分发给用户")
	@RequestMapping(path = "/messages", method = RequestMethod.POST)
	@ResponseBody
	public MessageDto createInformation(@RequestBody MessageDto dto) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		MessageTopics mess = new MessageTopics();
		BeanUtils.copyProperties(dto, mess);
		if (StringUtils.isNotBlank(dto.getIsDialog())) {
			mess.setIsDialog(DialogStatus.from(dto.getIsDialog()));
		}
		if (StringUtils.isNotBlank(dto.getFlagForm())) {
			mess.setFlagForm(FlagForm.from(dto.getFlagForm()));
		}
		if (StringUtils.isBlank(dto.getType())) {
			mess.setType("user");
		}
		mess.setCreateTime(new Date());
		this.messageTopicsRepository.save(mess);
		log.debug("finish create createInformation:{}", mess);
		dto.setInformID(mess.getMessageID());
		dto.setTopicsID(mess.getMessageID());
		dto.setCreateTime(sdf.format(mess.getCreateTime()));
		if (mess.getIsDialog() == null) {
			dto.setIsDialog(DialogStatus.notDialog.name());
		} else {
			dto.setIsDialog(mess.getIsDialog().name());
		}
		if (mess.getFlagForm() == null) {
			dto.setFlagForm(FlagForm.envelope.name());
		} else {
			dto.setFlagForm(mess.getFlagForm().getValue());
		}
		/** 分发给各个用户阶段 */
		this.messageRepository.deliver2messages(dto.getTitle(), dto.getContent(), mess.getType(),
				dto.getFlagForm() + "_" + dto.getIsDialog(), dto.getTopicsID(), mess.getCreateTime());

		return dto;
	}

	@ApiOperation(value = "删除不基于用户消息并且删除分发出去的消息")
	@RequestMapping(path = "/messages", method = RequestMethod.DELETE)
	@ResponseBody
	public List<MessageDto> delInformation(
			@RequestParam(name = "inform_id", defaultValue = "0", required = false) long informID) {
		List<MessageDto> dtos = new ArrayList<MessageDto>();
		if (informID > 0) {
			/** 删除的message_topics表数据 */
			MessageTopics topics = this.messageTopicsRepository.findByMessageID(informID);
			if (topics != null) {
				MessageDto dto = new MessageDto();
				BeanUtils.copyProperties(topics, dto);
				dto.setFlagForm(topics.getFlagForm().getValue());
				dto.setIsDialog(topics.getIsDialog().name());
				dto.setTopicsID(topics.getMessageID());
				this.messageTopicsRepository.delete(topics);
				dtos.add(dto);
			}
			/** 删除的user_message_delivery表数据 */
			this.messageRepository.deleteByTopicsID(informID);
		}
		return dtos;
	}

	@ApiOperation(value = "查看不基于用户所有消息")
	@RequestMapping(path = "/messages", method = RequestMethod.GET)
	@ResponseBody
	public List<MessageDto> findInformation() {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		List<MessageDto> dtos = new ArrayList<MessageDto>();
		List<MessageTopics> messes = (List<MessageTopics>) this.messageTopicsRepository.findAll();
		if (messes != null && messes.size() > 0) {
			for (MessageTopics mess : messes) {
				MessageDto dto = new MessageDto();
				dto.setTopicsID(mess.getMessageID());
				dto.setContent(mess.getContent());
				dto.setFlagForm(mess.getFlagForm().name());
				dto.setIsDialog(mess.getIsDialog().name());
				dto.setTitle(mess.getTitle());
				dto.setCreateTime(sdf.format(mess.getCreateTime()));

				dtos.add(dto);
			}
		}

		return dtos;
	}

	@ApiOperation(value = "查看不基于/基于用户的所有消息并分页")
	@RequestMapping(method = RequestMethod.GET, path = "/messages/actions")
	@ResponseBody
	public Page<LogDto<LogDto.LogNoteable>> findInformation(
			@RequestParam(name = "user_id", defaultValue = "0") long userID,
			@RequestParam(name = "type", defaultValue = "user") String type,
			@RequestParam(name = "page_num", defaultValue = "0") int page,
			@RequestParam(name = "page_size", defaultValue = "20") int size) {
		PageRequest pr = new PageRequest(page, size);
		Date today = DateUtils.truncate(new Date(), Calendar.DATE);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Page<LogDto<LogDto.LogNoteable>> dtos = null;

		List<LogDto<LogDto.LogNoteable>> list = new ArrayList<LogDto<LogDto.LogNoteable>>();
		if (userID != 0) {
			Page<Message> messes = this.messageRepository.findByTypeAndUserIDAndCreateTimeBeforeOrderByCreateTimeDesc(
					type, userID, DateUtils.addDays(today, +1), pr);
			for (Message mess : messes) {
				LogDto<LogNoteable> dto = new LogDto<LogNoteable>();
				BeanUtils.copyProperties(mess, dto);
				dto.setName(mess.getTitle());
				dto.setCreateTime(sdf.format(mess.getCreateTime()));
				if (StringUtils.isNotBlank(mess.getSubType())) {
					String[] arr = mess.getSubType().split("_");
					dto.setFlagForm(arr[0]);
					dto.setIsDialog(arr[1]);
				}
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, messes.getTotalElements());
		} else {
			Page<MessageTopics> messes = this.messageTopicsRepository
					.findByCreateTimeBeforeOrderByCreateTimeDesc(DateUtils.addDays(today, +1), pr);
			for (MessageTopics mess : messes) {
				LogDto<LogNoteable> dto = new LogDto<LogNoteable>();
				dto.setName(mess.getTitle());
				dto.setInformID(mess.getMessageID());
				dto.setCreateTime(sdf.format(mess.getCreateTime()));
				list.add(dto);
			}
			dtos = new PageImpl<LogDto<LogDto.LogNoteable>>(list, pr, messes.getTotalElements());
		}

		return dtos;
	}

	/**
	 * 创建基于用户信息
	 * 
	 * @param userID
	 * @param dto
	 * @return
	 */
	@ApiOperation(value = "创建基于用户消息")
	@RequestMapping(path = "/users/{user_id}/messages", method = RequestMethod.POST)
	@ResponseBody
	public MessageDto createMessage(@PathVariable("user_id") long userID, @RequestBody MessageDto dto) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		User user = this.userRepository.findOne(userID);
		Assert.notNull(userID, "user_not_found");
		Message mess = new Message();
		BeanUtils.copyProperties(dto, mess);
		mess.setUserID(userID);
		mess.setNick(user.getNick());
		if (StringUtils.isBlank(dto.getCreateTime())) {
			mess.setCreateTime(new Date());
		} else {
			try {
				mess.setCreateTime(sdf.parse(dto.getCreateTime()));
			} catch (ParseException e) {
				mess.setCreateTime(new Date());
				log.error("JsonProcessingException:{}", e);
			}
		}
		mess.setLastModifeTime(new Date());
		mess.setUnread(0);
		this.messageRepository.save(mess);
		log.debug("finish create message:{}", mess);
		dto.setInformID(mess.getInformID());

		return dto;
	}

	/**
	 * 查看所有信息
	 * 
	 * @param userID
	 * @param containerID
	 * @param unread
	 * @return
	 */
	@ApiOperation(value = "查看用户的某类型消息")
	@RequestMapping(path = "/users/{user_id}/messages", method = RequestMethod.GET)
	@ResponseBody
	public List<MessageDto> findMessage(@PathVariable("user_id") long userID,
			@RequestParam(name = "container_id", defaultValue = "0", required = false) long containerID,
			@RequestParam(required = false, defaultValue = "0") int unread,
			@RequestParam(name = "type", required = false, defaultValue = "message") String type) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date today = DateUtils.truncate(new Date(), Calendar.DATE);
		List<MessageDto> dtos = new ArrayList<MessageDto>();
		List<Message> messes = null;
		if (type.equals("news")) {
			messes = this.messageRepository.findByUserIDAndTypeAndCreateTimeBeforeOrderByCreateTimeDesc(userID, "user",
					DateUtils.addDays(today, +1));
		} else {
			messes = this.messageRepository.findByUserIDAndContainerIDAndUnread(userID, containerID, unread);
		}
		if (messes != null && messes.size() > 0) {
			for (Message mess : messes) {
				MessageDto dto = new MessageDto();
				BeanUtils.copyProperties(mess, dto);
				dto.setCreateTime(sdf.format(mess.getCreateTime()));
				dtos.add(dto);
			}
		}
		return dtos;
	}

	/**
	 * 查看单个消息
	 * 
	 * type:默认：user 后台：background
	 * 
	 * @param userID
	 * @param messageID
	 * @return
	 * 
	 */
	@ApiOperation(value = "查看单个消息")
	@RequestMapping(path = "/messages/{message_id}", method = RequestMethod.GET)
	@ResponseBody
	public MessageDto findMessageOne(@PathVariable("message_id") long messageID,
			@RequestParam(name = "type", defaultValue = "user") String type) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		MessageDto dto = new MessageDto();
		if (type.equals("user")) {
			Message mess = this.messageRepository.findOne(messageID);
			Assert.notNull(mess, "mess_not_foud");
			BeanUtils.copyProperties(mess, dto);
			dto.setCreateTime(sdf.format(mess.getCreateTime()));
		} else {
			MessageTopics topic = this.messageTopicsRepository.findOne(messageID);
			Assert.notNull(topic, "mess_not_foud");
			BeanUtils.copyProperties(topic, dto);
			dto.setCreateTime(sdf.format(topic.getCreateTime()));
		}

		return dto;
	}

	/**
	 * 修改基于用户的信息
	 * 
	 * @param userID
	 * @param messageID
	 */
	@ApiOperation(value = "修改基于用户某个未读消息的状态")
	@RequestMapping(path = "/users/{user_id}/messages/{message_id}/@read", method = RequestMethod.PUT)
	@ResponseBody
	public MessageDto updateMessage(@PathVariable("user_id") long userID, @PathVariable("message_id") long messageID) {
		Message mess = this.messageRepository.findOne(messageID);
		Assert.notNull(mess, "mess_not_foud");
		MessageDto dto = new MessageDto();
		log.debug("updateMessage: {}", messageID);
		mess.setUnread(1);
		mess.setLastModifeTime(new Date());
		this.messageRepository.save(mess);
		dto.setUnread(mess.getUnread());

		return dto;
	}

	@Data
	@JsonInclude(Include.NON_DEFAULT)
	public static class MessageDto {
		@JsonProperty("inform_id")
		private long informID = -1;
		@JsonProperty("user_id")
		private long userID = -1;
		private String nick;
		@JsonProperty("container_id")
		private long containerID = -1;
		@JsonProperty("content_type")
		private String type;
		@JsonProperty("content")
		private String content;
		@JsonProperty("create_time")
		@JsonFormat(shape = Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
		private String createTime;
		@JsonProperty("read")
		private int unread = -1;
		@JsonProperty("container_url")
		private String containerUrl;

		@JsonProperty("flag_form")
		private String flagForm;// 消息标签形式
		@JsonProperty("is_dialog")
		private String isDialog;// 是否弹窗;1:弹窗 0:不弹窗(默认)
		private String title; // 消息标题
		@JsonProperty("topics_id")
		private long topicsID = -1;
		@JsonProperty("sub_type")
		private String subType;
	}

	@ApiOperation(value = "用户/宝贝的效果数据均值")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "date_source", defaultValue = "pc", allowableValues = "pc, mobile", paramType = "query", dataType = "string") })
	@ResponseBody
	@RequestMapping(path = "/users/{user_id}/reports/average", method = RequestMethod.GET)
	public EffectMetricDto AvgMetric(@PathVariable("user_id") long userID, @RequestParam(name = "date") int date,
			@RequestParam(name = "date_source") String device,
			@RequestParam(name = "adgroup_id", defaultValue = "0") long adgroupID) {
		log.info("AvgMetric RequestParam userId:{} device:{} date:{}", userID, device, date);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		int lower = 1;
		int upper = 2;
		if (device.equals("mobile")) {
			lower = 4;
			upper = 5;
		}

		EffectMetricDto dto = new EffectMetricDto();
		RptKeyword rpt = new RptKeyword();
		if (adgroupID > 0) {
			rpt = this.readRptKeywordMapper.reportUserAverage(userID, adgroupID,
					DateFormatUtils.format(DateUtils.addDays(yesterday, -date + 1), "yyyy-MM-dd"),
					DateFormatUtils.format(yesterday, "yyyy-MM-dd"), lower, upper);
		} else {
			rpt = this.readRptKeywordMapper.reportUserAverage(userID, 0,
					DateFormatUtils.format(DateUtils.addDays(yesterday, -date + 1), "yyyy-MM-dd"),
					DateFormatUtils.format(yesterday, "yyyy-MM-dd"), lower, upper);
		}
		if (rpt != null) {
			dto.filterNull(rpt);
			dto.addSemiautoDimension(rpt);
			dto.from(rpt);
		}
		return dto;
	}

	@ApiOperation(value = "用户/宝贝的效果数据总值")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "date_source", defaultValue = "pc", allowableValues = "pc, mobile", paramType = "query", dataType = "string") })
	@ResponseBody
	@RequestMapping(path = "/users/{user_id}/reports/sum", method = RequestMethod.GET)
	public EffectMetricDto SumMetric(@PathVariable("user_id") long userID, @RequestParam(name = "date") int date,
			@RequestParam(name = "date_source") String device,
			@RequestParam(name = "adgroup_id", defaultValue = "0") long adgroupID) {
		log.info("MaxMetric RequestParam userId:{} device:{} date:{}", userID, device, date);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		int lower = 1;
		int upper = 2;
		if (device.equals("mobile")) {
			lower = 4;
			upper = 5;
		}
		EffectMetricDto dto = new EffectMetricDto();
		RptKeyword rpt = new RptKeyword();
		if (adgroupID > 0) {
			rpt = this.readRptKeywordMapper.reportUserSum(userID, adgroupID,
					DateFormatUtils.format(DateUtils.addDays(yesterday, -date + 1), "yyyy-MM-dd"),
					DateFormatUtils.format(yesterday, "yyyy-MM-dd"), lower, upper);
		} else {
			rpt = this.readRptKeywordMapper.reportUserSum(userID, 0,
					DateFormatUtils.format(DateUtils.addDays(yesterday, -date + 1), "yyyy-MM-dd"),
					DateFormatUtils.format(yesterday, "yyyy-MM-dd"), lower, upper);
		}
		if (rpt != null) {
			dto.filterNull(rpt);
			dto.addSemiautoDimension(rpt);
			dto.from(rpt);
		}
		return dto;
	}

	@ApiOperation(value = "用户/宝贝的效果数据最大值")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "date_source", defaultValue = "pc", allowableValues = "pc, mobile", paramType = "query", dataType = "string") })
	@ResponseBody
	@RequestMapping(path = "/users/{user_id}/reports/max", method = RequestMethod.GET)
	public EffectMetricDto MaxMetric(@PathVariable("user_id") long userID, @RequestParam(name = "date") int date,
			@RequestParam(name = "date_source") String device,
			@RequestParam(name = "adgroup_id", defaultValue = "0") long adgroupID) {
		log.info("MaxMetric RequestParam userId:{} device:{} date:{}", userID, device, date);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		int lower = 1;
		int upper = 2;
		if (device.equals("mobile")) {
			lower = 4;
			upper = 5;
		}
		EffectMetricDto dto = new EffectMetricDto();
		RptKeyword rpt = new RptKeyword();
		if (adgroupID > 0) {
			rpt = this.readRptKeywordMapper.reportMax(userID, adgroupID,
					DateFormatUtils.format(DateUtils.addDays(yesterday, -date + 1), "yyyy-MM-dd"),
					DateFormatUtils.format(yesterday, "yyyy-MM-dd"), lower, upper);
		} else {
			rpt = this.readRptKeywordMapper.reportMax(userID, 0,
					DateFormatUtils.format(DateUtils.addDays(yesterday, -date + 1), "yyyy-MM-dd"),
					DateFormatUtils.format(yesterday, "yyyy-MM-dd"), lower, upper);
		}
		if (rpt != null) {
			dto.filterNull(rpt);
			dto.addSemiautoDimension(rpt);
			dto.from(rpt);
		}
		return dto;
	}

	/**
	 * 指标摘要
	 * 
	 * @return
	 */
	@ApiOperation(value = "用户的效果数据摘要")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "pc, mobile", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/users/{user_id}/summaries/metric", method = RequestMethod.GET)
	public @ResponseBody EffectMetricDto summariesMetric(@PathVariable("user_id") Long userId,
			@RequestParam(required = false, defaultValue = "all") String device,
			@RequestParam(name = "days", defaultValue = "0") int days,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("summariesMetric RequestParam userId:{} device:{} startDate:{} endDate:{} day:{}", userId, device,
				startDate, endDate, days);
		RptCustomerParam param = new RptCustomerParam();
		param.setTaobaoUserId(userId);
		param.setupDevice(device);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		if (days > 0) {
			startDate = DateFormatUtils.format(DateUtils.addDays(yesterday, -days + 1), FORMAT_DAY);
			endDate = DateFormatUtils.format(yesterday, FORMAT_DAY);
		}
		if (StringUtils.isNotBlank(startDate)) {
			param.setupDate(startDate, endDate);
		}

		RptCustomer rpt = rptCustomerService.selectSums(param);

		EffectMetricDto dto = new EffectMetricDto();
		if (rpt != null) {
			dto.from(rpt);
		}
		return dto;
	}

	@ApiOperation(value = "首页用户的效果数据摘要")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "pc, mobile", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/users/{user_id}/summaries/metricWithPage", method = RequestMethod.GET)
	@ResponseBody
	public EffectMetricDto summariesMetricWithPage(@PathVariable("user_id") Long userId,
			@RequestParam(required = false, defaultValue = "all") String device,
			@RequestParam(name = "days", defaultValue = "0") int days,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("summariesMetricWithPage RequestParam userId:{} device:{} startDate:{} endDate:{}", userId, device,
				startDate, endDate);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		if (days > 0) {
			startDate = DateFormatUtils.format(DateUtils.addDays(yesterday, -days + 1), "yyyy-MM-dd");
			endDate = DateFormatUtils.format(yesterday, "yyyy-MM-dd");
		}

		int lower = 1;
		int upper = 5;
		if (device.equals("mobile")) {
			lower = 4;
			upper = 5;
		} else if (device.equals("pc")) {
			lower = 1;
			upper = 2;
		}

		RptCustomer rpt = rptCustomerMapper.selectUserMetricSum(userId, startDate, endDate, lower, upper);

		EffectMetricDto dto = new EffectMetricDto();
		if (rpt != null) {
			dto.from(rpt);
		}
		return dto;
	}

	@ApiOperation(value = "首页用户每天的效果数据趋势")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "all,pc, mobile", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/users/{userId}/reports/trendWithPage", method = RequestMethod.GET)
	public @ResponseBody List<EffectMetricDto> userEffectMetricPage(@PathVariable("userId") Long userId,
			@RequestParam(required = false, defaultValue = "all") String device,
			@RequestParam(name = "days", defaultValue = "0") int days,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("userEffectMetricPage RequestParam userId:{} device:{} startDate:{} endDate:{}", userId, device,
				startDate, endDate);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		if (days > 0) {
			startDate = DateFormatUtils.format(DateUtils.addDays(yesterday, -days + 1), "yyyy-MM-dd");
			endDate = DateFormatUtils.format(yesterday, "yyyy-MM-dd");
		}

		int lower = 1;
		int upper = 5;
		if (device.equals("mobile")) {
			lower = 4;
			upper = 5;
		} else if (device.equals("pc")) {
			lower = 1;
			upper = 2;
		}

		List<RptCustomer> rpts = rptCustomerMapper.selectUserTrendSum(userId, startDate, endDate, lower, upper);
		List<EffectMetricDto> dtos = new ArrayList<EffectMetricDto>();
		if (rpts != null) {
			for (RptCustomer rpt : rpts) {
				EffectMetricDto dto = new EffectMetricDto();
				dto.from(rpt);
				dtos.add(dto);
			}
		}

		return dtos;
	}

	/**
	 * 趋势
	 * 
	 * @return
	 */
	@ApiOperation(value = "用户每天的效果数据趋势")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "all", allowableValues = "all,pc, mobile", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/users/{userId}/reports/trend", method = RequestMethod.GET)
	public @ResponseBody List<EffectMetricDto> userEffectMetric(@PathVariable("userId") Long userId,
			@RequestParam(required = false, defaultValue = "all") String device,
			@RequestParam(name = "days", defaultValue = "0") int days,
			@RequestParam(name = "start_date", required = false) String startDate,
			@RequestParam(name = "end_date", required = false) String endDate) {
		log.info("reportsTrend RequestParam userId:{} device:{} startDate:{} endDate:{}", userId, device, startDate,
				endDate);
		RptCustomerParam param = new RptCustomerParam();
		param.setTaobaoUserId(userId);
		param.setupDevice(device);
		Date yesterday = DateUtils.addDays(DateUtils.truncate(new Date(), Calendar.DATE), -1);
		if (days > 0) {
			startDate = DateFormatUtils.format(DateUtils.addDays(yesterday, -days + 1), FORMAT_DAY);
			endDate = DateFormatUtils.format(yesterday, FORMAT_DAY);
		}

		if (StringUtils.isNotBlank(startDate)) {
			param.setupDate(startDate, endDate);
		}

		List<RptCustomer> rpts = rptCustomerService.selectStat(param);
		List<EffectMetricDto> dtos = new ArrayList<EffectMetricDto>();
		if (rpts != null) {
			for (RptCustomer rpt : rpts) {
				EffectMetricDto dto = new EffectMetricDto();
				dto.from(rpt);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@ApiOperation(value = "用户所有推广计划的效果数据摘要")
	@ApiImplicitParams({
			@ApiImplicitParam(name = "device", defaultValue = "pc", allowableValues = "pc, mobile", paramType = "query", dataType = "string") })
	@RequestMapping(path = "/users/{user_id}/reports/campaignStates", method = RequestMethod.GET)
	public @ResponseBody List<EffectMetricDto> campaignStates(@PathVariable("user_id") Long userId,
			@RequestParam(defaultValue = "0") int days, @RequestParam(required = false) String device,
			@RequestParam(required = false) String startDate, @RequestParam(required = false) String endDate) {
		log.info("campaignStates RequestParam userId:{} days:{} device:{} startDate:{} endDate:{}", userId, days,
				device, startDate, endDate);
		RptKeywordParam param = RptKeywordParam.init();
		param.setUserId(userId);
		if (device != null) {
			param.setupDevice(device);
		}
		if (days > 0) {
			param.setupDays(days);
		}
		if (startDate != null) {
			param.setupDate(startDate, endDate);
		}
		List<RptKeyword> rpts = rptKeywordService.getReportsTrend(param);
		List<EffectMetricDto> dtos = new ArrayList<EffectMetricDto>();
		if (rpts != null) {
			for (RptKeyword rpt : rpts) {
				EffectMetricDto dto = new EffectMetricDto();
				dto.filterNull(rpt);
				dto.from(rpt);
				dtos.add(dto);
			}
		}
		return dtos;
	}

	@ApiOperation(value = "用户的实时帐户信息")
	@RequestMapping(path = "/users/{user_id}/reports/realtimeAccount", method = RequestMethod.GET)
	@ResponseBody
	// TODO 加是否catch字段
	public DeferredResult<UserDto> findUserRealtimeAccount(@PathVariable("user_id") long userID,
			@RequestParam(name = "cache", required = false) boolean needCache,
			@RequestParam(name = "rtr_cust", defaultValue = "true") boolean needRtrCust) {
		User user = this.userRepository.findOne(userID);
		if (user == null) {
			throw new IllegalArgumentException("user_not_foud");
		}
		final DeferredResult<UserDto> result = new DeferredResult<UserDto>();
		UserDto dto = new UserDto();

		Date today = org.apache.commons.lang3.time.DateUtils.truncate(new Date(), Calendar.DATE);
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		UserLevelReport userLevel;
		float yesterday = 0;
		for (int i = 1; i <= 5; i++) {
			userLevel = this.userLevelReportRepository.findByUserIDAndDateAndSource(user.getUserID(),
					org.apache.commons.lang3.time.DateUtils.addDays(today, -1), i);
			if (userLevel != null && userLevel.getCost() != 0) {
				yesterday = yesterday + userLevel.getCost();
			}
		}
		float yesterdayCost = (float) (Math.round((yesterday / 100) * 100)) / 100;
		dto.setYesterdayCost(yesterdayCost);

		result.onTimeout(new Runnable() {
			@Override
			public void run() {
				SimbaProxyBaseDto timeoutRet = new SimbaProxyBaseDto();
				timeoutRet.setError(new SimbaProxyBaseDto.Error());
				timeoutRet.getError().setCode(500);
				timeoutRet.getError().setMessage("timeout");
				timeoutRet.getError().setSubCode("timeout");
				timeoutRet.getError().setSubMessage("超时");
				result.setErrorResult(timeoutRet);
				log.error("timeout findUserRealtimeAccount {}", userID);
			}
		});

		log.debug("finish sync rtrCust:{}", dto);

		// 从缓存获取当天的余额，如果获取不到则从淘宝获取存入mogo
		String accountBalanceId = DateFormatUtils.format(new Date(), "yyyyMMdd") + "_" + userID;
		AccountBalance accountBalance = accountBalanceRepository.findOne(accountBalanceId);
		if (needCache && accountBalance != null) {
			dto.setBalance(accountBalance.getBalance());
			result.setResult(dto);
			return result;
		} else {
			GetBalanceResponse balanRes = this.userClient.findBalance(user.getNick());
			log.debug("start sync balance:{}", balanRes);
			if (balanRes != null && balanRes.getRes() != null) {
				float balance = (float) (Math.round(balanRes.getRes().getBalance() * 100)) / 100;
				dto.setBalance(balance);

				accountBalance = new AccountBalance();
				accountBalance.setId(accountBalanceId);
				accountBalance.setUserID(userID);
				accountBalance.setBalance(balance);
				accountBalance.setCreateTime(new Date());
				accountBalanceRepository.save(accountBalance);

			} else {
				if (balanRes != null && balanRes.getError() != null) {
					BalanceAndRealtimeCostErrorLog errorLog = new BalanceAndRealtimeCostErrorLog(); // 错误信息保存到mongodb中
					errorLog.from(user);
					try {
						errorLog.setErrorCode(objectMapper.writeValueAsString(balanRes.getError()));
					} catch (JsonProcessingException e) {
						errorLog.setErrorCode("unknown-error");
						log.error("JsonProcessingException:{}", e);
					}

					if ("Invalid session".equals(balanRes.getError().getMessage())) {
						dto.setSubMessage("抱歉,您的授权已过期!");
					}

					if (balanRes.getError().getSubCode() != null) {
						errorLog.setSubCode(balanRes.getError().getSubCode());
					}
					if (balanRes.getError().getSubMessage() != null) {
						errorLog.setSubMessage(balanRes.getError().getSubMessage());

						if (balanRes.getError().getSubMessage().equals("直通车主账号不存在")
								|| balanRes.getError().getSubMessage().equals("users对象为空，无法根据userId获取用户信息")) {
							dto.setSubMessage("您还未开通直通车!");
						}
					}
					this.balanceAndRealtimeCostErrorLogRepository.save(errorLog);

					dto.setBlanError(balanRes.getError());
					dto.setErrorStatus(true);
					result.setResult(dto);
					return result;
				}
			}
		}

		if (needRtrCust) {
			GetRtrCustResponse res = this.userClient.findRtrCust(user.getNick(), sdf.format(today));
			log.debug("start sync rtrCust:{}", res);
			if (res != null && res.getRes() != null && res.getRes().getResultList() != null
					&& res.getRes().getResultList().getResult() != null) {
				List<GetRtrCustDto> dtos = res.getRes().getResultList().getResult();
				for (GetRtrCustDto rtrDto : dtos) {
					float tempReal = (float) (Long.parseLong(rtrDto.getCost())) / 100;
					float realCost = (float) (Math.round(tempReal * 100)) / 100;
					dto.setRealCost(realCost);
				}
			} else {
				if (res != null && res.getError() != null) {
					BalanceAndRealtimeCostErrorLog errorLog = new BalanceAndRealtimeCostErrorLog(); // 错误信息保存到mongodb中
					errorLog.from(user);
					try {
						errorLog.setErrorCode(objectMapper.writeValueAsString(res.getError()));
					} catch (JsonProcessingException e) {
						errorLog.setErrorCode("unknown-error");
						log.error("JsonProcessingException:{}", e);
					}
					if (res.getError().getSubCode() != null) {
						errorLog.setSubCode(res.getError().getSubCode());
					}
					if (res.getError().getSubMessage() != null) {
						errorLog.setSubMessage(res.getError().getSubMessage());
					}
					this.balanceAndRealtimeCostErrorLogRepository.save(errorLog);
					dto.setRtrError(res.getError());
					dto.setErrorStatus(true);
					result.setResult(dto);
					return result;
				}
			}
		}

		result.setResult(dto);
		log.debug("finish sync balance:{}", dto);
		return result;
	}

	@ApiOperation(value = "是否绑定错误主账号")
	@RequestMapping(path = "/users/{user_id}/wrong", method = RequestMethod.GET)
	@ResponseBody
	public Boolean wrongUser(@PathVariable("user_id") long userID) {
		// 代理用户绑定错误主账号
		List<Long> userIds = new ArrayList<Long>();
		boolean failUser = false;
		userIds.add(1657149315l);
		userIds.add(1657370240l);
		userIds.add(2380061785l);
		userIds.add(2659058328l);
		List<User> users = userRepository.findByAuthorizedToIn(userIds);
		if (users != null && users.size() > 0) {
			for (User user : users) {
				if (userID == user.getUserID()) {
					failUser = true;
					break;
				}
			}
		}
		return failUser;
	}

	@Data
	@JsonInclude(Include.NON_NULL)
	public static class UserDto {
		@JsonProperty("real_day_cost")
		private float realCost = -1f; // 单位为元
		@JsonProperty("balance")
		private float balance = -1f;
		@JsonProperty("yesterday_cost")
		private float yesterdayCost; // 单位为元
		@JsonProperty("is_error")
		private boolean errorStatus; // 是否调用直通车失败
		@JsonProperty("sub_message")
		private String subMessage = "";

		private SimbaProxyBaseDto.Error rtrError; // 实时扣费错误信息
		private SimbaProxyBaseDto.Error blanError;// 余额错误信息
	}
}
